package com.yuandian.management.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuandian.api.management.entity.*;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.bpm.common.security.util.SecurityUtils;
import com.yuandian.enums.ResultCodeEnum;
import com.yuandian.management.mapper.ConfUnconfirmedUrlMapper;
import com.yuandian.management.service.ConfBlackListService;
import com.yuandian.management.service.ConfComponentResourceService;
import com.yuandian.management.service.ConfConfirmedUrlService;
import com.yuandian.management.service.ConfUnconfirmedUrlService;
import com.yuandian.management.vo.UnconfirmedResourceVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 未确认URL资源表-Service实现
 * @author zfsn
 * @date 2023-3-16
 */
@Service
public class ConfUnconfirmedUrlServiceImpl extends ServiceImpl<ConfUnconfirmedUrlMapper, ConfUnconfirmedUrl>
		implements ConfUnconfirmedUrlService {

	@Autowired
	private ConfUnconfirmedUrlMapper confUnconfirmedUrlMapper;

	@Lazy
	@Autowired
	private ConfComponentResourceService confComponentResourceService;

	@Autowired
	private ConfConfirmedUrlService confConfirmedUrlService;

	@Autowired
	private ConfBlackListService confBlackListService;

	/**
	 * 分页查询
	 *
	 * @param confUnconfirmedUrl 筛选条件
	 * @return 通用返回对象
	 */
	@Override
	public Page<ConfUnconfirmedUrl> listPage(ConfUnconfirmedUrl confUnconfirmedUrl) {
		return confUnconfirmedUrlMapper.listPage(new Page<>(confUnconfirmedUrl.getPageNum(), confUnconfirmedUrl.getPageSize()),confUnconfirmedUrl);
	}

	/**
	 * 分页查询
	 *
	 * @param confUnconfirmedUrl 筛选条件
	 * @return 通用返回对象
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<String> confirmResource(ConfUnconfirmedUrl confUnconfirmedUrl) {
		QueryWrapper<ConfUnconfirmedUrl> queryWrapper = new QueryWrapper<>();
		queryWrapper.like("ori_url", confUnconfirmedUrl.getOriUrl());
		long num = super.count(new LambdaQueryWrapper<ConfUnconfirmedUrl>()
				.like(ConfUnconfirmedUrl::getOriUrl, confUnconfirmedUrl.getOriUrl()));

		if(0 == num){
			return R.failed(ResultCodeEnum.NO_MATCH_UNCONFIRM_RESOURCE.getMsg());
		}
		//判断服务资源表中是否有重复数据
		if(checkResourceDuplicates(confUnconfirmedUrl)){
			return R.failed(ResultCodeEnum.SERVER_RESOURCE_EXIT.getMsg());
		}

		// 保存在服务资源表 confConponentResource 中
		List<Map<String, Integer>> componentAndSegmentIds = new ArrayList<>();
		for (Integer segmentId : confUnconfirmedUrl.getSegmentIds()) {
			Map<String, Integer> map = new HashMap<>();
			ConfComponentResource confComponentResource = new ConfComponentResource();
			confComponentResource.setSegmentId(segmentId);
			confComponentResource.setIdentifyStr(confUnconfirmedUrl.getConfirmUrl());
			confComponentResource.setSystemId(confUnconfirmedUrl.getSystemId());

			LambdaQueryWrapper<ConfComponentResource> lambdaQueryWrapper = Wrappers.lambdaQuery();
			lambdaQueryWrapper.eq(ConfComponentResource::getSegmentId, segmentId);
			lambdaQueryWrapper.eq(ConfComponentResource::getIdentifyStr, confUnconfirmedUrl.getConfirmUrl());
			lambdaQueryWrapper.eq(ConfComponentResource::getSystemId, confUnconfirmedUrl.getSystemId());
			if (confComponentResourceService.count(lambdaQueryWrapper) > 0) {
				confComponentResource.setCreateBy(SecurityUtils.getUser().getName());
				confComponentResource.setCreateTime(LocalDateTime.now());
				confComponentResourceService.save(confComponentResource);
				map.put("componentServerResourceId", confComponentResourceService.list(Wrappers.query(confComponentResource)).get(0).getId());
				map.put("segmentId", segmentId);
				componentAndSegmentIds.add(map);
			}
		}

		//将符合条件未确认的资源 移动到 已确认的业务资源表中, 同时在conf_unconfirmed_url 删除对应的数据
		moveToComfirmTable(confUnconfirmedUrl, componentAndSegmentIds);
		return R.ok();
	}

	/**
	 * 添加黑名单
	 *
	 * @param confUnconfirmedUrl 筛选条件
	 * @return 通用返回对象
	 */
	@Override
	public R<String> addBlackListBatch(ConfUnconfirmedUrl confUnconfirmedUrl) {
		R result = R.ok();
		for (String prefixUrl : confUnconfirmedUrl.getPrefixUrls()) {
			confUnconfirmedUrl.setSourceStatus(0);
			 result = addBlackList(confUnconfirmedUrl, prefixUrl);
		}

		return result;
	}


	/**
	 * 加入黑名单
	 * @param urv 参数
	 * @param prefixUrl
	 * @return Result
	 */
	@Transactional(rollbackFor = Exception.class)
	public R addBlackList(ConfUnconfirmedUrl urv, String prefixUrl) {
		int status = 0;
		// 来源
		Integer sourceStatus = urv.getSourceStatus();

		if (sourceStatus != null) {
			if (sourceStatus == 0) {
				// 来自前缀
				// 1、查询符合前缀(允许被前端修改过)的未确认服务资源
				// 用前缀去匹配原始url
				urv.setOriUrl(prefixUrl);
				urv.setPrefixUrl(null);
				List<ConfUnconfirmedUrl> unconfirmedResourcelist = confUnconfirmedUrlMapper.queryListByCondition(urv);
				if (unconfirmedResourcelist.isEmpty()) {
					// 没有符合条件的未确认服务资源
					return R.failed(null , "符合" + prefixUrl + "前缀的未确认服务资源不存在");
				}

				// 2、将符合条件的未确认服务资源批量加入到黑名单
				List<Long> unconfirmedResourceIds = new ArrayList<>();
				List<ConfBlacklistResource> blacklistResourceList = new ArrayList<>();
				String username = SecurityUtils.getUser().getName();
				unconfirmedResourcelist.forEach(unconfirmedResource -> {
					unconfirmedResourceIds.add(Long.valueOf(unconfirmedResource.getId()));
					ConfBlacklistResource blacklistResource = new ConfBlacklistResource();
					blacklistResource.setDeleteTime(LocalDateTime.now());
					blacklistResource.setSourceStatus(sourceStatus);
					blacklistResource.setPrefixUrl(unconfirmedResource.getPrefixUrl());
					blacklistResource.setOriginalUrl(unconfirmedResource.getOriUrl());
					blacklistResource.setConfirmedUrl(prefixUrl);
					blacklistResource.setUpdateBy(username);
					blacklistResourceList.add(blacklistResource);
				});
				status = confBlackListService.insertBlackListResourceBatch(blacklistResourceList);
				if (status <= 0) {
					// 写入服务资源黑名单表失败
					return R.failed(null, "加入黑名单时，批量写入服务资源黑名单表失败");
				}

				// 3、批量删除符合前缀(允许被前端修改过)的未确认服务资源
				status = confUnconfirmedUrlMapper.deleteByIdBatch(unconfirmedResourceIds);
				if (status <= 0) {
					// 删除未确认服务资源失败
					return R.failed(null, "加入黑名单时，批量删除未确认服务资源失败");
				}
			} else if (sourceStatus == 1) {
				// 来自原始URL
				ConfBlacklistResource blacklistResource = new ConfBlacklistResource();
				blacklistResource.setDeleteTime(LocalDateTime.now());
				blacklistResource.setSourceStatus(sourceStatus);
				// 1、将未确认服务资源加入到黑名单
				blacklistResource.setPrefixUrl(prefixUrl);
				blacklistResource.setOriginalUrl(urv.getOriUrl());
				blacklistResource.setConfirmedUrl(urv.getConfirmUrl());
				status = confBlackListService.insertBlackListResource(blacklistResource);
				if (status <= 0) {
					// 写入服务资源黑名单表失败
					return R.failed(null, "加入黑名单时，写入服务资源黑名单表失败");
				}
				// 2、删除这条未确认服务资源
				status = confUnconfirmedUrlMapper.deleteById(urv.getId());
				if (status <= 0) {
					// 删除未确认服务资源失败
					return R.failed(null, "加入黑名单时，删除未确认服务资源失败");
				}
			}


			return R.ok();
		}else {
			return R.failed(null,"加入黑名单错误!");
		}
	}

	/**
	 * 条件查询未确认服务资源列表
	 *
	 * @param confSegmentResourceRelation
	 * @return
	 */
	@Override
	public List<ConfUnconfirmedUrl> prefixUrlMatch(ConfSegmentResourceRelation confSegmentResourceRelation) {
		return confUnconfirmedUrlMapper.prefixUrlMatch(confSegmentResourceRelation);
	}

	/**
	 * 分页查询url映射列表
	 *
	 * @param confUnconfirmedUrl
	 * @return
	 */
	@Override
	public Page<ConfUnconfirmedUrl> getUrlMappingPage(ConfUnconfirmedUrl confUnconfirmedUrl) {
		return confUnconfirmedUrlMapper.getUrlMappingPage(new Page<>(confUnconfirmedUrl.getPageNum(), confUnconfirmedUrl.getPageSize()),confUnconfirmedUrl);
	}

	@Override
	public List<ConfUnconfirmedUrl> queryListByCondition(UnconfirmedResourceVo urv) {
		return confUnconfirmedUrlMapper.queryListByUrl(urv);
	}

	@Override
	public Integer updateBusinessResourceNoUsed(String identifyStr) {
		return confUnconfirmedUrlMapper.updateBusinessResourceNoUsed(identifyStr);
	}

	/**
	 * 将符合条件未确认的资源 移动到 已确认的业务资源表中, 同时在conf_unconfirmed_url 删除对应的数据
	 * @param confUnconfirmedUrl
	 * @param componentAndSegmentIds
	 */
	private void moveToComfirmTable(ConfUnconfirmedUrl confUnconfirmedUrl, List<Map<String, Integer>> componentAndSegmentIds) {
		QueryWrapper<ConfUnconfirmedUrl> queryQuery = new QueryWrapper<>();
		queryQuery.like("ori_url", confUnconfirmedUrl.getOriUrl());
		List<ConfUnconfirmedUrl> confUnconfirmedUrls = super.list(queryQuery);

		QueryWrapper<ConfConfirmedUrl> queryQueryConfirmedUrl = new QueryWrapper<>();
		queryQueryConfirmedUrl.eq("system_id", confUnconfirmedUrl.getSystemId());
		queryQueryConfirmedUrl.eq("confirmed_url", confUnconfirmedUrl.getOriUrl());
		List<ConfConfirmedUrl> confConfirmedUrls = confConfirmedUrlService.list(queryQueryConfirmedUrl);

		if (confUnconfirmedUrls.isEmpty() && confConfirmedUrls.isEmpty())  return;

		for (ConfUnconfirmedUrl unconfirmedUrl : confUnconfirmedUrls) {
			for (Map<String, Integer> componentAndSegmentId : componentAndSegmentIds) {
				ConfConfirmedUrl confConfirmedUrl = new ConfConfirmedUrl();
				BeanUtils.copyProperties(unconfirmedUrl, confConfirmedUrl);
				confConfirmedUrl.setResourceComponentId(componentAndSegmentId.get("componentServerResourceId"));
				confConfirmedUrl.setSystemId(unconfirmedUrl.getSystemId());
				confConfirmedUrl.setConfirmedUrl(unconfirmedUrl.getConfirmUrl());
				confConfirmedUrl.setStatus(0);
				confConfirmedUrl.setSegmentId(Integer.valueOf(componentAndSegmentId.get("segmentId")));
			}
		}

		confConfirmedUrlService.saveBatch(confConfirmedUrls);
		super.removeBatchByIds(confUnconfirmedUrls.stream().map(ConfUnconfirmedUrl::getId).collect(Collectors.toList()));
	}

	/**
	 * 判断服务资源是否存在
	 * @return
	 * @param confUnconfirmedUrl 筛选对象
	 */
	private boolean checkResourceDuplicates(ConfUnconfirmedUrl confUnconfirmedUrl) {
		QueryWrapper<ConfComponentResource> queryQuery = new QueryWrapper<>();
		queryQuery.eq("system_id", confUnconfirmedUrl.getSystemId());
		queryQuery.eq("resource_code", confUnconfirmedUrl.getResourceCode());
		queryQuery.ne("id", confUnconfirmedUrl.getId());
		return confComponentResourceService.count(queryQuery) > 0 ;
	}
}
